package cn.lwalan.commonUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 线程安全的时间转换类
 * https://blog.csdn.net/zxh87/article/details/19414885
 * @Auther: Alan liu
 * @Date: 2019/2/14 15:33
 * @Description: SafetyDateUtil
 */
public class SafetyDateUtil {

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static  String formatDate(Date date)throws ParseException {
        return sdf.format(date);
    }

    public static Date parse(String strDate) throws ParseException{
        return sdf.parse(strDate);
    }

    /**
     * 方法1
     * 哪里用到SimpleDateFormat就new出个实例进行使用，
     * 在需要用到SimpleDateFormat 的地方新建一个实例，不管什么时候，
     * 将有线程安全问题的对象由共享变为局部私有都能避免多线程问题，
     * 不过也加重了创建对象的负担。在一般情况下，这样其实对性能影响比不是很明显的。
     * @param date
     * @return
     * @throws ParseException
     */
    public static  String formatDateSafe(Date date)throws ParseException{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static Date parseSafe(String strDate) throws ParseException{
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.parse(strDate);
    }

    /**
     * 方法2
     * 使用同步：同步SimpleDateFormat对象
     * 当线程较多时，当一个线程调用该方法时，其他想要调用此方法的线程就要block，多线程并发量大的时候会对性能有一定的影响。
     * @param date
     * @return
     * @throws ParseException
     */
    public static  String formatDateSafe2(Date date)throws ParseException{
        synchronized(sdf){
            return sdf.format(date);
        }
    }

    public static Date parseSafe2(String strDate) throws ParseException{
        synchronized(sdf){
            return sdf.parse(strDate);
        }
    }

    /**
     * 方法3
     *.使用ThreadLocal
     * @param date
     * @return
     * @throws ParseException
     */
    public static  String formatDateSafe3(Date date)throws ParseException{
        return threadLocal.get().format(date);
    }

    private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    public static Date parseSafe3(String strDate) throws ParseException{
        return threadLocal.get().parse(strDate);
    }

    /**
     * 方法3
     * 使用ThreadLocal
     */
    private static final String date_format = "yyyy-MM-dd HH:mm:ss";
    private static ThreadLocal<DateFormat> threadLocal2 = new ThreadLocal<DateFormat>();
    public static DateFormat getDateFormat()
    {
        DateFormat df = threadLocal2.get();
        if(df==null){
            df = new SimpleDateFormat(date_format);
            threadLocal2.set(df);
        }
        return df;
    }

    public static String formatDateSafe31(Date date) throws ParseException {
        return getDateFormat().format(date);
    }

    public static Date parseSafe31(String strDate) throws ParseException {
        return getDateFormat().parse(strDate);
    }
}

